package com.yilin.platform.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.yilin.platform.base_core.application.MathUtil;
import com.yilin.platform.base_core.commons.exception.BusinessException;
import com.yilin.platform.base_core.commons.utils.*;
import com.yilin.platform.base_core.tools.wechat.WeChatUtils;
import com.yilin.platform.entity.capital.TradeFlow;
import com.yilin.platform.entity.cmbc.CmbcTradeRecord;
import com.yilin.platform.entity.user.deserialize.HatchWechat;
import com.yilin.platform.entity.weChat.WeChatTradeRecord;
import com.yilin.platform.mapper.weChat.WeChatTradeRecordMapper;
import com.yilin.platform.service.IWeChatService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.util.*;

@Service
public class WeChatService extends ServiceImpl<WeChatTradeRecordMapper, WeChatTradeRecord> implements IWeChatService {
    private Logger logger = LoggerFactory.getLogger(WeChatService.class);
    @Value("${plat-product-code}")
    private String platProductCode;//平台产品代码
    @Resource
    private WeChatTradeRecordMapper weChatTradeRecordMapper;
    @Resource
    private UserService userService;
    @Resource
    private TradeFlowService tradeFlowService;

    private HatchWechat hatchWechat;

    public HatchWechat getHatchWechat() {
        if (hatchWechat == null) { // 第一次检查，未创建时进入同步块
            synchronized (this) {
                if (hatchWechat == null) { // 双重检查，确保只有一个线程创建对象
                    Map<String, Object> param = MapUtil.generate(map -> map.put("productCode", platProductCode));
                    hatchWechat = userService.request("/user/hatch/getWechatHatchByCode", null, param, new TypeToken<HatchWechat>() {});
                }
            }
        }
        return hatchWechat;
    }

    /*微信app下单*/
    @Override
    public Map<String, Object> wxChartAppTransactions(WeChatTradeRecord weChatTradeRecord) {
        Map<String, Object> amountJson = new HashMap<>();
        Integer amt = new BigDecimal(String.valueOf(weChatTradeRecord.getTranAmount())).multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_EVEN).intValue();
        amountJson.put("total", amt);
        amountJson.put("currency", "CNY");
        Map<String, Object> param = new HashMap<>();
        String userType = String.valueOf(weChatTradeRecord.getUserType());
        param.put("appid", getHatchWechat().getAppId(userType));
        param.put("mchid", getHatchWechat().getMchId(userType));
        param.put("description", weChatTradeRecord.getTradeName());
        param.put("out_trade_no", weChatTradeRecord.getTradeNo());
        param.put("notify_url", getHatchWechat().getNotifyBackUrl() + "/platform/weChat/weChartPayBack/" + userType);
        param.put("amount", amountJson);
        try {
            logger.info("微信app支付请求数据" + new Gson().toJson(param));
            Map<String, Object> response = WeChatUtils.weChatV3Post(getHatchWechat(), userType, param, "https://api.mch.weixin.qq.com/v3/pay/transactions/app");
            logger.info("微信app支付返回数据" + new Gson().toJson(response));
            weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.handle);
            weChatTradeRecord.setInitiateTime(new Date());
            weChatTradeRecord.setWeChatTradeType(WeChatTradeRecord.WeChatTradeType.payment);
            weChatTradeRecord.setWeChatType(WeChatTradeRecord.WeChatType.app);
            weChatTradeRecord.setQueryWaitCount(0);
            weChatTradeRecord.setSyncTaskCount(0);
            weChatTradeRecord.setNextWaitTime(new Date());
            weChatTradeRecord.setNextNotificationTime(new Date());
            saveOrUpdate(weChatTradeRecord);
            String timestamp = System.currentTimeMillis() / 1000 + "";  //时间戳
            String nonceStr = UUID.randomUUID().toString().replace("-", ""); //随机串
            String sign = WeChatUtils.getSign(nonceStr, timestamp, new Gson().toJson(param), getHatchWechat().getPrivateKeyUrl(userType), "GET");
            Map<String, Object> map = new HashMap<>();
            map.put("prepayid", response.get("prepay_id"));
            map.put("timestamp", timestamp);
            map.put("noncestr", nonceStr);
            map.put("sign", sign);
            map.put("appid", getHatchWechat().getAppId(userType));
            map.put("package", "Sign=WXPay");
            map.put("partnerid", getHatchWechat().getMchId(userType));
            map.put("universalLink", getHatchWechat().getUniversalLink(userType));//用于唤起APP
            return map;
        } catch (Exception e) {
            logger.info("微信支付APP发起支付异常" + e.getMessage());
            throw new BusinessException("微信支付APP发起支付异常" + e.getMessage());
        }
    }

    /*微信app下单*/
    @Override
    public Map<String, Object> wxChartAppTransactionsH5(WeChatTradeRecord weChatTradeRecord) {
        Map<String, Object> amountJson = new HashMap<>();
        Integer amt = new BigDecimal(String.valueOf(weChatTradeRecord.getTranAmount())).multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_EVEN).intValue();
        amountJson.put("total", amt);
        amountJson.put("currency", "CNY");
        Map<String, Object> param = new HashMap<>();
        String userType = String.valueOf(weChatTradeRecord.getUserType());
        param.put("appid", getHatchWechat().getAppId(userType));
        param.put("mchid", getHatchWechat().getMchId(userType));
        param.put("description", weChatTradeRecord.getTradeName());
        param.put("out_trade_no", weChatTradeRecord.getTradeNo());
        param.put("notify_url", getHatchWechat().getNotifyBackUrl() + "/platform/weChat/weChartPayBack/" + userType);
        param.put("amount", amountJson);
        try {
            logger.info("微信H5支付请求数据" + new Gson().toJson(param));
            Map<String, Object> response = WeChatUtils.weChatV3Post(getHatchWechat(), userType, param, "https://api.mch.weixin.qq.com/v3/pay/transactions/native");
            logger.info("微信H5支付返回数据" + new Gson().toJson(response));
            weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.handle);
            weChatTradeRecord.setWeChatTradeType(WeChatTradeRecord.WeChatTradeType.payment);
            weChatTradeRecord.setInitiateTime(new Date());
            weChatTradeRecord.setWeChatType(WeChatTradeRecord.WeChatType.app);
            weChatTradeRecord.setQueryWaitCount(0);
            weChatTradeRecord.setSyncTaskCount(0);
            weChatTradeRecord.setNextWaitTime(new Date());
            weChatTradeRecord.setNextNotificationTime(new Date());
            saveOrUpdate(weChatTradeRecord);
            Map<String, Object> map = new HashMap<>();
            map.put("code_url", response.get("code_url"));
            return map;
        } catch (Exception e) {
            logger.error("微信支付H5发起支付异常" + e.getMessage());
            throw new BusinessException("微信支付H5发起支付异常" + e.getMessage());
        }
    }

    /*微信app支付查询
     * 备注：调这个方法之后需要掉用订单通知接口
     * */
    @Override
    public WeChatTradeRecord wxChartAppQueryTransactions(String tradeNo) {
        try {
            WeChatTradeRecord weChatTradeRecord = getWeChatTradeRecordByTradeNo(tradeNo);
            ParamUtil.isNull(weChatTradeRecord, "获支付单为null");
            String userType = String.valueOf(weChatTradeRecord.getUserType());
            String url = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/" + weChatTradeRecord.getTradeNo() + "?mchid=" + getHatchWechat().getMchId(userType);
            logger.info("微信app支付查询请求数据" + new Gson().toJson(url));
            Map<String, Object> response = WeChatUtils.weChatV3Get(getHatchWechat(), userType, url);
            logger.info("微信app支付查询返回数据" + new Gson().toJson(response));
            String state = MapUtil.getMapString(response, "trade_state");
            if (MapUtil.getMapString(response, "transaction_id") != null)
                weChatTradeRecord.setBankFlowNo(MapUtil.getMapString(response, "transaction_id"));
            if (MapUtil.getMapString(response, "trade_state_desc") != null && weChatTradeRecord.getRemark() == null)
                weChatTradeRecord.setRemark(MapUtil.getMapString(response, "trade_state_desc"));
            if (MapUtil.getMapString(response, "success_time") != null)
                weChatTradeRecord.setCompleteTime(DateTimeUtil.wxStringToDate(MapUtil.getMapString(response, "success_time"), null));
            Map<String, Object> payer = (Map<String, Object>) response.get("payer");
            if (weChatTradeRecord.getOutAcctNo() == null)
                weChatTradeRecord.setOutAcctNo(MapUtil.getMapString(payer, "openid"));
            if (weChatTradeRecord.getInAcctNo() == null) weChatTradeRecord.setInAcctNo(getHatchWechat().getMchId(userType));
            if (state.equals("SUCCESS") || state.equals("REFUND")) {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.success);
            } else if (state.equals("CLOSED")) {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.close);
            } else if (state.equals("PAYERROR")) {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.fail);
            } else if (state.equals("NOTPAY")) {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.notpay);
            } else {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.handle);
            }
            saveTradeFlow(weChatTradeRecord.getTradeName(), weChatTradeRecord);
            saveOrUpdate(weChatTradeRecord);
            return weChatTradeRecord;
        } catch (Exception e) {
            logger.error("微信支付APP支付查询异常" + e.getMessage());
            throw new BusinessException("微信支付APP支付查询异常" + e.getMessage());
        }
    }

    /*微信app发起退款*/
    @Override
    public WeChatTradeRecord wxChartAppRefund(WeChatTradeRecord weChatTradeRecord, WeChatTradeRecord tradeRecordOrgin) {
        try {
            Map<String, Object> amountJson = new HashMap<>();
            amountJson.put("refund", CommonUtil.intValue(MathUtil.multiply(weChatTradeRecord.getTranAmount(), 100D)));
            amountJson.put("total", CommonUtil.intValue(MathUtil.multiply(tradeRecordOrgin.getTranAmount(), 100D)));
            amountJson.put("currency", "CNY");
            String userType = String.valueOf(tradeRecordOrgin.getUserType());
            Map<String, Object> param = MapUtil.generate(map -> {
                map.put("out_trade_no", tradeRecordOrgin.getTradeNo());
                map.put("out_refund_no", weChatTradeRecord.getTradeNo());
                map.put("reason", weChatTradeRecord.getRemark());
                map.put("notify_url", getHatchWechat().getNotifyBackUrl() + "/platform/weChat/weChartRefundBack/" + userType);
                map.put("amount", amountJson);
            });
            logger.info("微信app支付退款请求数据" + new Gson().toJson(param));
            Map<String, Object> response = WeChatUtils.weChatV3Post(getHatchWechat(), userType, param, "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds");
            logger.info("微信app支付退款返回数据" + new Gson().toJson(response));
            String state = MapUtil.getMapString(response, "status");
            weChatTradeRecord.setBankFlowNo(MapUtil.getMapString(response, "refund_id"));
            weChatTradeRecord.setWeChatTradeType(WeChatTradeRecord.WeChatTradeType.refund);
            weChatTradeRecord.setUserType(tradeRecordOrgin.getUserType());
            if (weChatTradeRecord.getOutAcctNo() == null)
                weChatTradeRecord.setOutAcctNo(tradeRecordOrgin.getInAcctNo());
            if (weChatTradeRecord.getInAcctNo() == null) weChatTradeRecord.setInAcctNo(tradeRecordOrgin.getOutAcctNo());
            if (state.equals("SUCCESS")) {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.success);
                weChatTradeRecord.setBankMsg(MapUtil.getMapString(response, "user_received_account"));
            } else if (state.equals("CLOSED")) {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.close);
            } else if (state.equals("ABNORMAL")) {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.fail);
            } else {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.handle);
            }
            weChatTradeRecord.setQueryWaitCount(0);
            weChatTradeRecord.setSyncTaskCount(0);
            weChatTradeRecord.setNextWaitTime(new Date());
            weChatTradeRecord.setNextNotificationTime(new Date());
            saveOrUpdate(weChatTradeRecord);
            return weChatTradeRecord;
        } catch (Exception e) {
            logger.error("微信支付APP发起退款异常" + e.getMessage());
            throw new BusinessException("微信支付APP发起退款异常" + e.getMessage());
        }
    }

    //公共: 保存流水
    private void saveTradeFlow(String tradeName, WeChatTradeRecord weChatTradeRecord) {
        if (weChatTradeRecord.getWeChatTradeStatus() != WeChatTradeRecord.WeChatTradeStatus.success) return;
        TradeFlow[] tradeFlows = tradeFlowService.generateTradeFlows(tradeName, TradeFlow.PayType.weixin, weChatTradeRecord);
        tradeFlowService.saveOrUpdateBatch(ArrayUtil.initList(tradeFlows));
    }

    /*微信app退款查询
     * 备注：调这个方法之后需要掉用订单通知接口
     * */
    @Override
    public WeChatTradeRecord wxChartAppQueryRefund(String tradeNo) {
        try {
            WeChatTradeRecord weChatTradeRecord = getWeChatTradeRecordByTradeNo(tradeNo);
            String userType = String.valueOf(weChatTradeRecord.getUserType());
            ParamUtil.isNull(weChatTradeRecord, "获支付单为null");
            String url = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/" + weChatTradeRecord.getTradeNo();
            logger.info("微信app支付退款查询请求数据" + new Gson().toJson(url));
            Map<String, Object> response = WeChatUtils.weChatV3Get(getHatchWechat(), userType, url);
            logger.info("微信app支付退款查询返回数据" + new Gson().toJson(response));
            String state = MapUtil.getMapString(response, "status");
            if (MapUtil.getMapString(response, "transaction_id") != null)
                weChatTradeRecord.setBankFlowNo(MapUtil.getMapString(response, "transaction_id"));
            if (MapUtil.getMapString(response, "success_time") != null)
                weChatTradeRecord.setCompleteTime(DateTimeUtil.wxStringToDate(MapUtil.getMapString(response, "success_time"), null));
            if (state.equals("SUCCESS")) {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.success);
                weChatTradeRecord.setBankMsg(MapUtil.getMapString(response, "user_received_account"));
                saveTradeFlow(weChatTradeRecord.getTradeName(), weChatTradeRecord);
            } else if (state.equals("CLOSED")) {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.close);
            } else if (state.equals("ABNORMAL")) {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.fail);
            } else {
                weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.handle);
            }
            saveOrUpdate(weChatTradeRecord);
            return weChatTradeRecord;
        } catch (Exception e) {
            logger.error("微信支付APP查询退款异常" + e.getMessage());
            throw new BusinessException("微信支付APP查询退款异常" + e.getMessage());
        }
    }


    @Override
    public Map<String, Object> weChatCallback(HttpServletRequest request, HttpServletResponse response, String userType, String type) {
        Map<String, Object> map = new HashMap<>();
        try {
            String body = readData(request);
            logger.info("微信支付付款回调数据" + body);
            String nonce = request.getHeader("Wechatpay-Nonce");  //随机串
            String signature = request.getHeader("Wechatpay-Signature");   //微信传递过来的签名
            String wechatPaySerial = request.getHeader("Wechatpay-Serial");  //证书序列号（微信平台）
            String timestamp = request.getHeader("Wechatpay-Timestamp"); //时间戳
            String mchId = getHatchWechat().getMchId(userType);
            String privateKey = getHatchWechat().getPrivateKeyUrl(userType);
            String serialNo = getHatchWechat().getSerialNo(userType);
            String apiV3Key = getHatchWechat().getApiV3Key(userType);
            PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(Files.newInputStream(Paths.get(privateKey)));
            // 获取证书管理器实例
            CertificatesManager certificatesManager = CertificatesManager.getInstance();
            // 向证书管理器增加需要自动更新平台证书的商户信息
            certificatesManager.putMerchant(mchId, new WechatPay2Credentials(mchId,
                            new PrivateKeySigner(serialNo, merchantPrivateKey)),
                    apiV3Key.getBytes(StandardCharsets.UTF_8));
            Verifier verifier = certificatesManager.getVerifier(mchId);
            NotificationRequest notificationRequest = new NotificationRequest.Builder().withSerialNumber(wechatPaySerial)
                    .withNonce(nonce)
                    .withTimestamp(timestamp)
                    .withSignature(signature)
                    .withBody(body)
                    .build();
            // 这个解析器是微信支付SDK里的，他会帮我们做验签等一系列的事，不需要我们去做
            NotificationHandler handler = new NotificationHandler(verifier, apiV3Key.getBytes(StandardCharsets.UTF_8));
            Notification notification = handler.parse(notificationRequest);
            String decryptData = notification.getDecryptData();
            JSONObject jsonObject = JSONObject.parseObject(decryptData);

            if (type.equals("payment")) {
                map = wxCallPay(jsonObject, mchId);
            } else if (type.equals("refund")) {
                map = wxCallPayRefund(jsonObject);
            } else {
                throw new BusinessException("回调地址错误平地址" + type);
            }
        } catch (Exception e) {
            map.put("code", "FAIL");
            map.put("message", "失败");
            logger.info("微信APP支付" + (type.equals("payment") ? "支付" : "退款") + "回调异常请检查：" + e.getMessage());
        }
        return map;
    }

    /*微信支付回调*/
    public Map<String, Object> wxCallPay(JSONObject jsonObject, String mchId) {
        Map<String, Object> map = new HashMap<>();
        String state = String.valueOf(jsonObject.get("trade_state"));
        String orderNumber = String.valueOf(jsonObject.get("out_trade_no"));
        WeChatTradeRecord weChatTradeRecord = getWeChatTradeRecordByTradeNo(orderNumber);
        if (weChatTradeRecord.getRemark() == null)
            weChatTradeRecord.setRemark(String.valueOf(jsonObject.get("attach")));
        weChatTradeRecord.setBankFlowNo(String.valueOf(jsonObject.get("transaction_id")));
        weChatTradeRecord.setCompleteTime(DateTimeUtil.wxStringToDate(String.valueOf(jsonObject.get("success_time")), null));
        Map<String, Object> payer = (Map<String, Object>) jsonObject.get("payer");
        if (weChatTradeRecord.getOutAcctNo() == null)
            weChatTradeRecord.setOutAcctNo(MapUtil.getMapString(payer, "openid"));
        if (weChatTradeRecord.getInAcctNo() == null) weChatTradeRecord.setInAcctNo(mchId);
        if (state.equals("SUCCESS") || state.equals("REFUND")) {
            weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.success);
        } else if (state.equals("CLOSED")) {
            weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.close);
        } else if (state.equals("PAYERROR")) {
            weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.fail);
        } else if (state.equals("NOTPAY")) {
            weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.notpay);
        } else {
            weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.handle);
        }
        try {
            saveTradeFlow(weChatTradeRecord.getTradeName(), weChatTradeRecord);
        } catch (Exception e) {
            logger.error("微信支付退款回调通知保存流水失败" + e.getMessage());
        }
        try {
                processNotificationStatus(Collections.singletonList(weChatTradeRecord));
        } catch (Exception e) {
            logger.error("微信支付回调通知失败" + e.getMessage());
        }
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        return map;
    }

    /*微信退款回调*/
    public Map<String, Object> wxCallPayRefund(JSONObject jsonObject) {
        Map<String, Object> map = new HashMap<>();
        String state = String.valueOf(jsonObject.get("refund_status"));
        String orderNumber = String.valueOf(jsonObject.get("out_refund_no"));
        WeChatTradeRecord weChatTradeRecord = getWeChatTradeRecordByTradeNo(orderNumber);
        weChatTradeRecord.setBankFlowNo(String.valueOf(jsonObject.get("refund_id")));
        weChatTradeRecord.setCompleteTime(DateTimeUtil.wxStringToDate(String.valueOf(jsonObject.get("success_time")), null));
        if (state.equals("SUCCESS")) {
            weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.success);
        } else if (state.equals("CLOSED")) {
            weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.close);
        } else if (state.equals("ABNORMAL")) {
            weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.fail);
        } else {
            weChatTradeRecord.setWeChatTradeStatus(WeChatTradeRecord.WeChatTradeStatus.handle);
        }
        try {
            saveTradeFlow(weChatTradeRecord.getTradeName(), weChatTradeRecord);
        } catch (Exception e) {
            logger.error("微信支付退款回调通知保存流水失败" + e.getMessage());
        }
        try {
            processNotificationStatus(Collections.singletonList(weChatTradeRecord));
        } catch (Exception e) {
            logger.error("微信支付退款回调通知失败" + e.getMessage());
        }
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        return map;
    }


    @Override
    public WeChatTradeRecord getWeChatTradeRecordById(String tradeRecordId) {
        return weChatTradeRecordMapper.selectById(tradeRecordId);
    }

    @Override
    public WeChatTradeRecord getWeChatTradeRecordByTradeNo(String tradeNo) {
        QueryWrapper<WeChatTradeRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("trade_no", tradeNo);
        queryWrapper.eq("is_deleted", 0);
        return weChatTradeRecordMapper.selectOne(queryWrapper);
    }

    @Override
    public List<WeChatTradeRecord> getNotificationList() {
        QueryWrapper<WeChatTradeRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.nested(i ->
                        i.or(j -> j.in("we_chat_trade_status", 3, 5).le("next_wait_time", new Date()))
                                .or(j -> j.eq("we_chat_trade_status", 1).eq("notified_yilin", 0))
                                .or(j -> j.eq("we_chat_trade_status", 2).eq("notified_yilin", 0))
                                .or(j -> j.eq("we_chat_trade_status", 4).eq("notified_yilin", 0)))
                .eq("is_deleted", 0)
                .le("next_notification_time", new Date());
        return weChatTradeRecordMapper.selectList(queryWrapper);
    }

    @Override
    public void myTaskOneMinute() {
        List<WeChatTradeRecord> recordFlowList = getNotificationList();
        if (recordFlowList == null || recordFlowList.isEmpty()) return;
        List<WeChatTradeRecord> recordSuccess = new ArrayList<>();
        List<WeChatTradeRecord> recordHandle = new ArrayList<>();
        for (WeChatTradeRecord weChatTradeRecord : recordFlowList) {
            try {
                weChatTradeRecord = getWeChatTradeRecord(weChatTradeRecord);
            } catch (Exception e) {
                logger.info("微信支付定时函数查询单笔转账异常：" + e.getMessage());
                recordHandle.add(getRecordHandle(weChatTradeRecord));
                continue;
            }
            if (isSuccessSuccess(weChatTradeRecord)) { //判断需要通知的
                recordSuccess.add(weChatTradeRecord);
            } else if (isSuccessHandle(weChatTradeRecord)) {//判断是否需要重新查询的
                recordHandle.add(getRecordHandle(weChatTradeRecord));
            }
        }
        if (!recordHandle.isEmpty()) saveOrUpdateBatch(recordHandle);
        if (!recordSuccess.isEmpty()) processNotificationStatus(recordSuccess);
    }


    //#######################################################内部方法#########################################################################

    //通知平台
    public void processNotificationStatus(List<WeChatTradeRecord> recordList) {
        List<Map<String, Object>> mapList = new ArrayList<>();
        for (int i = 0; i < recordList.size(); i++) {
            String state;
            if (recordList.get(i).getWeChatTradeStatus() == WeChatTradeRecord.WeChatTradeStatus.success) {
                state = "paySuccess";
            } else if (recordList.get(i).getWeChatTradeStatus() == WeChatTradeRecord.WeChatTradeStatus.fail) {
                state = "payFail";
            } else if (recordList.get(i).getWeChatTradeStatus() == WeChatTradeRecord.WeChatTradeStatus.close) {
                state = "close";
            } else if (recordList.get(i).getWeChatTradeStatus() == WeChatTradeRecord.WeChatTradeStatus.notpay) {
                state = "create";
            } else {
                continue;
            }
            int finalI = i;
            mapList.add(MapUtil.generate(map1 -> {
                map1.put("tradeNo", recordList.get(finalI).getTradeNo());
                map1.put("tradeStatus", state);
                if (StringUtil.isNotEmpty(recordList.get(finalI).getBankFlowNo())) map1.put("bankFlowNo", recordList.get(finalI).getBankFlowNo());
                if (recordList.get(finalI).getCompleteTime() != null) map1.put("finishTime", recordList.get(finalI).getCompleteTime());
                if (StringUtil.isNotEmpty(recordList.get(finalI).getOutAcctNo())) map1.put("paymentCapitalAccount", recordList.get(finalI).getOutAcctNo());
                if (StringUtil.isNotEmpty(recordList.get(finalI).getInAcctNo())) map1.put("incomeCapitalAccount", recordList.get(finalI).getInAcctNo());
                if (StringUtil.isNotEmpty(recordList.get(finalI).getBankMsg())) map1.put("tradeFailMsg", recordList.get(finalI).getBankMsg());
            }));
        }
        if(!mapList.isEmpty())return;
        Map<String, Object> paramMap = MapUtil.generate(map -> {
            map.put("tradeResults", new Gson().toJson(mapList));
            map.put("payType", "wxPay");
            map.put("bankType", "none");
        });
        String status = null;
        try {
            paramMap.put("jsonResult", new ObjectMapper().writeValueAsString(recordList));
            status = userService.request("/capital/callback/bankPayResult", null, paramMap, new TypeToken<String>() {
            });
        } catch (JsonProcessingException e) {
            handleException(recordList, e);
        }
        if (status == null) return;
        for (WeChatTradeRecord recordFlow : recordList) {
            if (status.equals("SUCCESS")) {
                recordFlow.setSyncTaskCount(0);
                recordFlow.setNotifiedYilin(true);
                recordFlow.setNotifyTime(new Date());
            } else {
                updateNotifiWeChatTradeRecordTime(recordFlow);
            }
        }
        saveOrUpdateBatch(recordList);

    }

    //设置通知异常
    private void handleException(List<WeChatTradeRecord> recordList, Exception e) {
        for (WeChatTradeRecord recordFlow : recordList) {
            updateNotifiWeChatTradeRecordTime(recordFlow);
        }
        saveOrUpdateBatch(recordList);
        logger.error("微信通知支付订单失败：错误信息：" + e.getMessage());
        throw new BusinessException(e.getMessage());
    }

    //设置下次通知时间
    private void updateNotifiWeChatTradeRecordTime(WeChatTradeRecord recordFlow) {
        recordFlow.setNextNotificationTime(DateTimeUtil.addTimeByCount(new Date(), recordFlow.getSyncTaskCount()));
        recordFlow.setSyncTaskCount(recordFlow.getSyncTaskCount() + 1);
    }

    //判断需要通知的
    private boolean isSuccessSuccess(WeChatTradeRecord weChatTradeRecord) {
        return weChatTradeRecord.getWeChatTradeStatus() != WeChatTradeRecord.WeChatTradeStatus.handle
                && weChatTradeRecord.getWeChatTradeStatus() != WeChatTradeRecord.WeChatTradeStatus.create
                && weChatTradeRecord.getWeChatTradeStatus() != WeChatTradeRecord.WeChatTradeStatus.notpay;
    }

    //判断是否需要重新查询的
    private boolean isSuccessHandle(WeChatTradeRecord weChatTradeRecord) {
        return weChatTradeRecord.getWeChatTradeStatus() == WeChatTradeRecord.WeChatTradeStatus.handle
                || weChatTradeRecord.getWeChatTradeStatus() == WeChatTradeRecord.WeChatTradeStatus.notpay;
    }

    //处理生成下次查询时间
    private WeChatTradeRecord getRecordHandle(WeChatTradeRecord weChatTradeRecord) {
        weChatTradeRecord.setNextWaitTime(DateTimeUtil.getWeChataAliPayTime(new Date(), weChatTradeRecord.getQueryWaitCount()));
        weChatTradeRecord.setQueryWaitCount(weChatTradeRecord.getQueryWaitCount() + 1);
        return weChatTradeRecord;
    }

    //    查询微信记录
    private WeChatTradeRecord getWeChatTradeRecord(WeChatTradeRecord weChatTradeRecord) {
        if (weChatTradeRecord.getWeChatTradeStatus() == WeChatTradeRecord.WeChatTradeStatus.handle) {
            if (weChatTradeRecord.getWeChatTradeType() == WeChatTradeRecord.WeChatTradeType.payment) {
                weChatTradeRecord = wxChartAppQueryTransactions(weChatTradeRecord.getTradeNo());
            } else if (weChatTradeRecord.getWeChatTradeType() == WeChatTradeRecord.WeChatTradeType.refund) {
                weChatTradeRecord = wxChartAppQueryRefund(weChatTradeRecord.getTradeNo());
            }
        }
        return weChatTradeRecord;
    }

    //读取微信回调数据
    public static String readData(HttpServletRequest request) {
        try (BufferedReader reader = request.getReader()) {
            String line;
            StringBuilder result = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                if (result.length() > 0) {
                    result.append("\n");
                }
                result.append(line);
            }
            return result.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
